<template>
  <div class="protocol-parser">
    <h2>协议解析器（小端序）</h2>

    <!-- 输入协议结构 -->
    <h3>协议结构 JSON：</h3>
    <textarea v-model="protocolText" class="input-area" rows="20"></textarea>

    <!-- 输入字节流 -->
    <h3>待解析字节（hex，空格分隔或紧凑格式均可）：</h3>
    <textarea v-model="hexInput" class="input-area" rows="5"></textarea>

    <button class="btn" @click="parse">解析</button>

    <h3>校验结果：</h3>
    <div v-if="errors.length === 0">✔ 没有错误</div>
    <ul v-else>
      <li v-for="e in errors" :key="e" style="color:red">{{ e }}</li>
    </ul>

    <h3>解析结果：</h3>
    <pre>{{ JSON.stringify(result, null, 2) }}</pre>
  </div>
</template>

<script setup>
import {ref} from "vue";

const protocolText = ref(JSON.stringify([
  {
    "name": "dst",
    "type": "u8",
    "size": 1,
    "count_from": null,
    "fields": null,
    "description": "目的进程号"
  },
  {
    "name": "src",
    "type": "u8",
    "size": 1,
    "count_from": null,
    "fields": null,
    "description": "源进程号"
  },
  {
    "name": "bodyLen",
    "type": "u16",
    "size": 2,
    "count_from": null,
    "fields": null,
    "description": "消息体长度"
  },
  {
    "name": "msgType",
    "type": "u8",
    "size": 1,
    "count_from": null,
    "fields": null,
    "description": "消息类型"
  },
  {
    "name": "mcu_ip",
    "type": "u32",
    "size": 4,
    "count_from": null,
    "fields": null,
    "description": "mcu ip"
  },
  {
    "name": "mcu_port",
    "type": "u16",
    "size": 2,
    "count_from": null,
    "fields": null,
    "description": "mcu 端口号"
  },
  {
    "name": "do_send",
    "type": "u8",
    "size": 1,
    "count_from": null,
    "fields": null,
    "description": "0表示不配置ATDM, 1 表示可配置ATDM"
  },
  {
    "name": "kde_no",
    "type": "u16",
    "size": 2,
    "count_from": null,
    "fields": null,
    "description": "KDE 编号"
  },
  {
    "name": "satellite_id",
    "type": "u16",
    "size": 2,
    "count_from": null,
    "fields": null,
    "description": "卫星编号"
  },
  {
    "name": "beam_count",
    "type": "u8",
    "size": 1,
    "count_from": null,
    "fields": null,
    "description": "波束个数"
  },
  {
    "name": "beams",
    "type": "array",
    "count_from": "beam_count",
    "fields": [
      {
        "name": "beam_id",
        "type": "u16",
        "size": 2,
        "count_from": null,
        "fields": null,
        "description": "波束Id"
      }
    ],
    "description": "波束列表"
  }
], null, 2));

const hexInput = ref(
    `5a 29 12 00 01 62 18 fb 30 1d 25 01 01 00 0c 00 03 20 00 23 00 2b 00`
);

const errors = ref([]);
const result = ref({});

// -----------------------------------------------------------
// 协议结构校验器
// -----------------------------------------------------------
function validateProtocolStructure(struct) {
  const errs = [];
  const basic = ["u8", "u16", "u32"];
  const seen = new Set();

  for (const field of struct) {
    seen.add(field.name);

    if (basic.includes(field.type)) {
      if (!("size" in field)) {
        errs.push(`基础类型字段 ${field.name} 必须包含 size`);
      }
    }

    if (field.type === "array") {
      if ("size" in field) {
        errs.push(`数组字段 ${field.name} 不应包含 size`);
      }
      if (!field.count_from) {
        errs.push(`数组字段 ${field.name} 必须包含 count_from`);
      }
      if (!seen.has(field.count_from)) {
        errs.push(`数组字段 ${field.name} 的 count_from "${field.count_from}" 未在之前定义`);
      }
      if (!Array.isArray(field.fields)) {
        errs.push(`数组字段 ${field.name} 的 fields 必须是数组`);
      }
    }

    if (field.type === "object") {
      if ("size" in field) {
        errs.push(`对象字段 ${field.name} 不应包含 size`);
      }
      if (!Array.isArray(field.fields)) {
        errs.push(`对象字段 ${field.name} 的 fields 必须是数组`);
      }
    }
  }

  return errs;
}

// -----------------------------------------------------------
// 字节解析（小端序）- 修复版
// -----------------------------------------------------------
function parseBytesLE(bytes, struct) {
  let offset = 0;
  const dataView = new DataView(bytes.buffer);

  // 先解析所有基本字段，构建上下文对象
  const context = {};

  for (const field of struct) {
    if (["u8", "u16", "u32"].includes(field.type)) {
      let value;
      switch (field.type) {
        case "u8":
          value = dataView.getUint8(offset);
          console.log("解析出 u8 " + field.name, value);
          break;
        case "u16":
          value = dataView.getUint16(offset, true);
          console.log("解析出 u16 " + field.name, value);
          break;
        case "u32":
          value = dataView.getUint32(offset, true);
          console.log("解析出 u32 " + field.name, value);
          break;
      }
      context[field.name] = value;
      offset += field.size;
    }
  }

  // 再解析数组字段
  const result = {...context};

  for (const field of struct) {
    if (field.type === "array") {
      const count = context[field.count_from];
      const arr = [];

      for (let i = 0; i < count; i++) {
        const item = {};
        for (const subField of field.fields) {
          let value;
          switch (subField.type) {
            case "u8":
              value = dataView.getUint8(offset);
              console.log("解析出 u8 " + subField.name, value);
              break;
            case "u16":
              value = dataView.getUint16(offset, true);
              console.log("解析出 u16 " + subField.name, value);
              break;
            case "u32":
              value = dataView.getUint32(offset, true);
              console.log("解析出 u32 " + subField.name, value);
              break;
          }
          item[subField.name] = value;
          offset += subField.size;
        }
        arr.push(item);
      }

      result[field.name] = arr;
    }
  }

  return result;
}

// -----------------------------------------------------------
// 执行解析
// -----------------------------------------------------------
function parse() {
  let struct = [];
  try {
    struct = JSON.parse(protocolText.value);
  } catch (e) {
    errors.value = ["协议结构 JSON 格式错误"];
    return;
  }

  errors.value = validateProtocolStructure(struct);
  if (errors.value.length > 0) {
    result.value = {};
    return;
  }

  // 清理并验证 HEX 输入
  let clean = hexInput.value.replace(/[^0-9a-fA-F]/g, "");

  // 必须是偶数长度
  if (clean.length % 2 !== 0) {
    errors.value = ["Hex 数据长度不是偶数，可能缺少一个半字节"];
    result.value = {};
    return;
  }

  // 转成字节数组
  const byteArr = [];
  for (let i = 0; i < clean.length; i += 2) {
    const hexByte = clean.slice(i, i + 2);
    const num = Number.parseInt(hexByte, 16);

    if (Number.isNaN(num)) {
      errors.value = [`无效 HEX 字节: ${hexByte}`];
      result.value = {};
      return;
    }

    byteArr.push(num);
  }

  const bytes = new Uint8Array(byteArr);

  try {
    result.value = parseBytesLE(bytes, struct);
  } catch (e) {
    errors.value = [`解析错误: ${e.message}`];
    result.value = {};
  }
}
</script>

<style scoped>
.protocol-parser {
  font-family: Arial;
  padding: 20px;
}

.input-area {
  width: 100%;
  font-family: monospace;
}

.btn {
  margin: 10px 0;
  padding: 6px 12px;
}
</style>